package com.oxygen.pt.service.impl;

import ch.qos.logback.classic.Logger;
import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.oxygen.pt.mapper.AnomalyRecordMapper;
import com.oxygen.pt.mapper.PatientMapper;
import com.oxygen.pt.mapper.TreatmentDetailMapper;
import com.oxygen.pt.mapper.TreatmentStatisticsMapper;
import com.oxygen.pt.pojo.dto.DistributionCabinDTO;
import com.oxygen.pt.pojo.dto.PatientDTO;
import com.oxygen.pt.pojo.entity.*;
import com.oxygen.pt.pojo.vo.*;
import com.oxygen.pt.service.PatientService;
import com.oxygen.pt.utils.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
public class PatientServiceImpl implements PatientService {

    @Resource
    private PatientMapper patientMapper;
    @Resource
    private RedisIdWorker redisIdWorker;
    @Resource
    private TreatmentDetailMapper treatmentDetailMapper;
    @Resource
    private AnomalyRecordMapper anomalyRecordMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private TreatmentStatisticsMapper treatmentStatisticsMapper;

    /**
     * 插入患者的详情，包括patient表的操作和treatment_detail表的操作
     */

    @Override
    public Result<String> add(PatientDTO patientDTO, Logger log) {
        //必填字段验证
        if (patientDTO.getName().isEmpty()){
            return Result.error("请输入患者名字");
        }
        if (patientDTO.getAge() == 0){
            return Result.error("请输入患者年龄");
        }
        if (patientDTO.getGender() == 0){
            return Result.error("请输入性别");
        }
        if (patientDTO.getPhone().isEmpty()){
            return Result.error("请输入患者联系方式");
        }
        if (patientDTO.getCostType().isEmpty()){
            return Result.error("请输入患者的医保类型");
        }

        try {
            // 2. DTO 转 Entity
            Patient patient = BeanUtil.copyProperties(patientDTO, Patient.class);

            // 3. ID 生成（如果数据库不是自增主键）
            Long nextId = redisIdWorker.nextId(RedisConstants.PT_ID);
            patient.setPatientId(nextId);

            // 4. 默认字段
            LocalDateTime now = LocalDateTime.now();
            patient.setCreateTime(Timestamp.valueOf(now));
            patient.setUpdateTime(Timestamp.valueOf(now));

            // 默认治疗状态：例如，0表示“未分配”或“未开始治疗”
            patient.setTreatmentStatus(PatientStatusConstants.REMARK_TO_ALLOCATE); // 假设是待分配状态
            // deleted: 逻辑删除标志，默认为未删除 (0)
            patient.setDeleted(0); // 确保设置逻辑删除标志
            // 5. 插入患者信息
            patientMapper.add(patient);

            // 6. 初始化治疗详情
            TreatmentDetail detail = new TreatmentDetail();
            detail.setPatientId(patient.getPatientId());
            detail.setCompletedSessions(0);
            detail.setRemainingSessions(patient.getPlanSessions());
            detail.setTotalSessions(patient.getPlanSessions());
            detail.setCreatedAt(Timestamp.valueOf(now));
            detail.setUpdatedAt(Timestamp.valueOf(now));
            treatmentDetailMapper.insert(detail);

            return Result.success(String.valueOf(patient.getPatientId())); // 修改这里，返回ID
        } catch (Exception e) {
            log.error("新增患者失败，详细错误：", e);
            return Result.error("新增患者失败，请联系管理员");
        }
    }
    @Override public boolean updatePatient(PatientDTO patientDTO) {
        System.out.println("Service层收到更新请求，但尚未实现具体更新逻辑。PatientDTO: " + patientDTO);
        return true;
    }
    @Override
    public PageInfo<PatientVO> getPatients(String costType, Integer gender, Long minAge,
                                           Long maxAge, Long personType, int page, int size) {
        // 开始分页
        PageHelper.startPage(page, size);

        // 数据库查询（会被分页拦截器处理）
        List<Patient> patients = patientMapper.selectPatients(costType, gender, minAge, maxAge, personType);

        // 基于原始查询结果创建PageInfo，此时包含正确的total等分页信息
        PageInfo<Patient> patientPageInfo = new PageInfo<>(patients);

        // 转换为VO列表
        List<PatientVO> patientsVo = patients.stream()
                .map(patient -> BeanUtil.copyProperties(patient, PatientVO.class))
                .collect(Collectors.toList());

        // 创建新的PageInfo并复制分页信息
        PageInfo<PatientVO> resultPageInfo = new PageInfo<>(patientsVo);
        resultPageInfo.setTotal(patientPageInfo.getTotal());
        resultPageInfo.setPages(patientPageInfo.getPages());
        resultPageInfo.setPageNum(patientPageInfo.getPageNum());
        resultPageInfo.setPageSize(patientPageInfo.getPageSize());
        // 可以根据需要复制其他分页属性

        return resultPageInfo;
    }

    /**
     * 根据id查询或者的详情信息
     * @param id 患者id
     * @return 患者详情VO
     */
    @Override
    public PatientVO getById(Long id) {
        Patient byId = patientMapper.getById(id);
        return BeanUtil.copyProperties(byId, PatientVO.class);
    }

    /**
     * 获取患者的详情，包括患者详情 诊断与治疗计划 治疗状态与进展
     * @param id 患者的id
     * @return 患者的详情信息
     */
    @Override
    public PatientDetailVO getDetailById(Long id) {
        //根据id查询患者的详情
        Patient patient = patientMapper.getById(id);
        //根据id查询患者对应的治疗详情
        TreatmentDetail detail = treatmentDetailMapper.getByPatientId(id);
        //将患者详情和患者的治疗详情传入患者详情VO的构造函数中
        //返回患者详情信息
        return PatientDetailVO.detailBuilder(patient, detail);
    }

    /**
     * 获取异常记录的分页查询
     * @return 获取日常记录
     */
    @Override
    public List<AnomalyRecordVO> getAnomalyList() {
        List<AnomalyRecord> anomalyRecords = anomalyRecordMapper.selectAll();
        List<AnomalyRecordVO> res = new ArrayList<>();
        anomalyRecords.forEach(
                anomalyRecord ->
                    res.add(BeanUtil.copyProperties(anomalyRecord,AnomalyRecordVO.class))
        );
        return res;
    }

    /**
     * 患者数据统计分析 - 治疗数据统计
     * @param unit unit(1: 周 2：月 3： 季度 4：本年)
     * @return TreatmentAnalysisVO 六个数据： 三个记录，三个百分比
     */
    @Override
    public TreatmentAnalysisVO treatmentData(Integer unit) {
        // 根据所选的unit 确定两个日期范围unit(1: 周 2：月 3： 季度 4：本年)
        DateScope dateScopeNow = new DateScope();
        DateScope dateScopeLast = new DateScope();

        if (unit.equals(1)){
            dateScopeNow = DateRangeUtils.getThisWeekRange();
            dateScopeLast = DateRangeUtils.getLastWeekRange();
        }else if (unit.equals(2)){
            dateScopeNow = DateRangeUtils.getThisMonthRange();
            dateScopeLast= DateRangeUtils.getLastMonthRange();
        }else if (unit.equals(3)){
            dateScopeNow = DateRangeUtils.getThisQuarterRange();
            dateScopeLast = DateRangeUtils.getLastQuarterRange();
        }else {
            dateScopeNow = DateRangeUtils.getThisYearRange();
            dateScopeLast = DateRangeUtils.getLastYearRange();
        }

        //计算新增患者的同比上涨
        Long patientNumNow = patientMapper.getNumByDate(dateScopeNow.getStartDate(),dateScopeNow.getEndDate());
        Long patientNumLast = patientMapper.getNumByDate(dateScopeLast.getStartDate(),dateScopeLast.getEndDate());

        //计算完成治疗的人数
        Long patientFinishNumNow = patientMapper.getNumByStatus(dateScopeNow.getStartDate(),
                dateScopeNow.getEndDate());
        Long patientFinishNumLast = patientMapper.getNumByStatus(dateScopeLast.getStartDate(),
                dateScopeLast.getEndDate());

        //计算异常记录数
        Long exceptionNumNow = anomalyRecordMapper.getByDate(dateScopeNow.getStartDate(),dateScopeNow.getEndDate());
        Long exceptionNumLast = anomalyRecordMapper.getByDate(dateScopeLast.getStartDate(),dateScopeLast.getEndDate());


        //计算同比上涨
        float percentPt = getPercent(patientNumNow, patientNumLast);
        float percentFinish = getPercent(patientFinishNumNow,patientFinishNumLast);
        float percentException = getPercent(exceptionNumNow,exceptionNumLast);

        //封装VO并返回
        return new TreatmentAnalysisVO(patientNumNow,
                patientFinishNumNow,exceptionNumNow,percentPt,percentFinish,percentException);
    }

    /**
     * 统计军队和地方人员你的数量
     * @return
     */
    @Override
    public ArmyAndPlaceVO getArmyAndPlaceNum() {
        //mapper层查询personType为1和为0的人数
        int placeNum = patientMapper.getByPersonType(PersonTypeConstants.PLACE_PERSON);
        //全量查询
        int armyNum = patientMapper.getByPersonType(null) - placeNum;
        return new ArmyAndPlaceVO(armyNum,placeNum);
    }

    @Override
    public PatientTypeNumCountVO getPatientTypeNumCount() {
        //统计地方人员
        int placeNum = patientMapper.getByPersonType(PersonTypeConstants.PLACE_PERSON);
        //统计军队人员
        int retireNum = patientMapper.getByPersonType(PersonTypeConstants.RETIRE_ARMY);
        int baseNum = patientMapper.getByPersonType(PersonTypeConstants.BASE_ARMY);
        int midNum = patientMapper.getByPersonType(PersonTypeConstants.MID_ARMY);
        int seniorNum = patientMapper.getByPersonType(PersonTypeConstants.SENIOR_ARMY);

        return new PatientTypeNumCountVO(
                placeNum,retireNum,baseNum,midNum,seniorNum
        );
    }

    /**
     * 为患者分配治疗的舱室舱号。
     * @param distributionCabinDTO  前端所传数据，包括患者id和选择的舱号
     */
    @Override
    public Result<Object> distributionCabin(DistributionCabinDTO distributionCabinDTO) {
        //Step1. 查询该舱余量是否还能容纳  不能则返回错误信息。
        int status = patientMapper.getStatusById(Long.valueOf(distributionCabinDTO.getPatient_id()));
        if (status ==2  ||status == 3){
            return Result.error("患者不处于可分配状态");
        }
        //0.依赖氧舱表，氧舱表种记录氧舱表的信息，容量、等等，
        //0.1 每天都刷新氧舱记录缓存(finish)
        //查询该氧舱号有没有余量
        String remindStr = (String) stringRedisTemplate.opsForHash().get(
                RedisConstants.CHAMBER_INFORMATION,
                String.valueOf(distributionCabinDTO.getCabinNumber())
        );
        int remind = Integer.parseInt(remindStr);

       if (remind>0){
           //修改氧舱的剩余的容量
           stringRedisTemplate.opsForHash().put(
                   RedisConstants.CHAMBER_INFORMATION,
                   String.valueOf(distributionCabinDTO.getCabinNumber()),
                   String.valueOf(remind-1));
           //修改患者的状态为“待开始治疗”
            patientMapper.updateStatus(Long.valueOf(distributionCabinDTO.getPatient_id()),
                    PatientStatusConstants.REMARK_TO_START);

            // 修改每日治疗记录表
           TreatmentStatistics treatmentStatistics = treatmentStatisticsMapper.selectByDate(LocalDate.now());
           treatmentStatistics.setAssigned(
                   treatmentStatistics.getAssigned() + 1
           );
           treatmentStatisticsMapper.updateByDate(treatmentStatistics);


           //使用Redis存储该患者被分配到了哪一个舱中，舱号为多少
           stringRedisTemplate.opsForHash().put(
                   RedisConstants.PATIENT_ALLOCATION,
                   String.valueOf(distributionCabinDTO.getPatient_id()),
                   String.valueOf(distributionCabinDTO.getCabinNumber())
           );


       }else {
           return Result.error("该氧舱的剩余容量不足");
       }
        return Result.success("成功分配患者");
    }

    /**
     * 修改患者的状态为取消分配
     * @param patientId 需要更改状态的患者id
     * @return 统一返回
     */
    @Override
    public Result<Object> cancelAllocation(Long patientId) {
        //0.获取患者的状态
        Integer status = patientMapper.getStatusById(patientId);
        //TODO： 今日是否已经治疗过， 查询redis set缓存。
        if (status !=  2){
            return Result.error("患者状态不处于已分配舱室状态");
        }

        //1. 修改患者的状态为待分配
        patientMapper.updateStatus(patientId,
                PatientStatusConstants.REMARK_TO_ALLOCATE);

        //修改每日治疗记录表数据  待分配+1 已分配-1
        TreatmentStatistics treatmentStatistics = treatmentStatisticsMapper.selectByDate(LocalDate.now());
        treatmentStatistics.setAssigned(
                treatmentStatistics.getAssigned() -1
        );
        treatmentStatistics.setPendingAssignment(
                treatmentStatistics.getPendingAssignment() + 1
        );
        treatmentStatisticsMapper.updateByDate(treatmentStatistics);

        //2.获取患者被分配到的几号舱
        String chamberNumString = (String) stringRedisTemplate
                .opsForHash().get(RedisConstants.PATIENT_ALLOCATION, patientId.toString());
        //3，删除已经分配的缓存
        stringRedisTemplate.opsForHash().delete(RedisConstants.PATIENT_ALLOCATION,patientId.toString());
        //4. 对该缓存中氧舱的余量进行+1
        String remindStr = (String) stringRedisTemplate.opsForHash().get(
                RedisConstants.CHAMBER_INFORMATION,
               chamberNumString
        );
        int remind = Integer.parseInt(remindStr);
        stringRedisTemplate.opsForHash()
                .put(RedisConstants.CHAMBER_INFORMATION,chamberNumString,String.valueOf(remind+1));
        return Result.success("患者成功取消分配");
    }

    /**
     * 插入异常记录
     * @param anomalyRecordVO 由前端传来的异常记录字段
     * @return 返回插入结果
     */
    @Override
    public Result<Object> insertAnomalyRecord(AnomalyRecordVO anomalyRecordVO) {
        AnomalyRecord anomalyRecord = BeanUtil.copyProperties(anomalyRecordVO, AnomalyRecord.class);
        anomalyRecord.setId(redisIdWorker.nextId("anomalyRecord"));
        anomalyRecord.setAnomalyTime(LocalDateTime.now());
        anomalyRecordMapper.insertAnomalyRecord(anomalyRecord);
        return Result.success("成功插入异常记录");
    }

    /**
     * 患者开始治疗 services
     * @param patientId 患者的ID
     * @return 返回操作结果
     */
    @Override
    public Result<Object> startTreatment(Long patientId) {
        //查询患者的状态
        Integer status = patientMapper.getStatusById(patientId);
        if(status != 2){
            return Result.error("患者当前状态不能开始治疗");
        }
        //修改患者状态
        patientMapper.updateStatus(patientId,PatientStatusConstants.REMARK_IN_TREATMENT);
        TreatmentStatistics treatmentStatistics = treatmentStatisticsMapper.selectByDate(LocalDate.now());
        treatmentStatistics.setAssigned(
                treatmentStatistics.getAssigned()  > 0 ? treatmentStatistics.getAssigned()-1 : 0
        );
        treatmentStatistics.setInTreatment(
                treatmentStatistics.getInTreatment() + 1
        );
        treatmentStatisticsMapper.updateByDate(treatmentStatistics);


        return Result.success("成功开始治疗");
    }

    /**
     * 患者完成治疗接口
     * @param patientId 患者id
     * @return 返回操作结果
     */
    @Override
    public Result<Object> finishTreatment(Long patientId) {
        //TODO：  待测试
        Integer status = patientMapper.getStatusById(patientId);
        if(status != 3){
            return Result.error("患者当前状态不能做此操作");
        }
        TreatmentDetail treatmentDetail = treatmentDetailMapper.getByPatientId(patientId);
        long remainingSessions = treatmentDetail.getRemainingSessions();
        if(remainingSessions == 1){
            //剩余治疗次数为1，更改患者的状态
            patientMapper.updateStatus(patientId,PatientStatusConstants.REMARK_COMPLETED);

            //记录Redis的缓存记录缓存，SET 今日完成的患者id
            LocalDate date = LocalDate.now();
            String cacheKey = RedisConstants.FINISH_TREATMENT + date.toString();
            stringRedisTemplate.opsForSet().add(cacheKey,patientId.toString());

        }else {
            //更改患者的状态
            // 依据查询的次数看看转化为 待分配还是完成治疗
            patientMapper.updateStatus(patientId,PatientStatusConstants.REMARK_TO_ALLOCATE);

            //修改缓存 氧舱余量和 患者分配到哪个舱的
            String chamberNumString = (String) stringRedisTemplate
                    .opsForHash().get(RedisConstants.PATIENT_ALLOCATION, patientId.toString());
            //3，删除已经分配的缓存
            stringRedisTemplate.opsForHash().delete(RedisConstants.PATIENT_ALLOCATION,patientId.toString());
            //4. 对该缓存中氧舱的余量进行+1
            String remindStr = (String) stringRedisTemplate.opsForHash().get(
                    RedisConstants.CHAMBER_INFORMATION,
                    chamberNumString
            );
            int remind = Integer.parseInt(remindStr);
        }

        //修改治疗详情
        treatmentDetail.setCompletedSessions(treatmentDetail.getCompletedSessions()+1);
        treatmentDetail.setRemainingSessions(treatmentDetail.getRemainingSessions() -1);
        treatmentDetail.setLastTreatmentDate(Timestamp.valueOf(LocalDateTime.now()));
        treatmentDetailMapper.updateTreatmentDetail(treatmentDetail);

        return Result.success("成功完成治疗");
    }

    @Override
    public boolean deletePatientById(Long id) {
        patientMapper.deleteById(id);
        return true;
    }

    @Override
    public PageInfo<AnomalyRecordVO> getAnomalyPage(Integer pageNum, Integer pageSize) {
        // 1. 设置分页参数（紧跟其后的第一次查询会被分页）
        PageHelper.startPage(pageNum, pageSize);
        // 2. 查询列表
        List<AnomalyRecordVO> list = anomalyRecordMapper.selectAnomalyList();
        // 3. 包装结果
        return new PageInfo<>(list);
    }

    /**
     * 计算当前时间单位和上一个时间单位的上涨幅度
     * @param patientNumNow 当前 日月年季度
     * @param patientNumLast 上一个日月年季度
     * @return 百分比
     */
    private float getPercent(Long patientNumNow, Long patientNumLast) {
        float diff = (float) (patientNumNow - patientNumLast);
        float percent = 0;
        if (!patientNumLast.equals(0L)){
            //如果分母不为零
            percent = diff/((float) patientNumLast);
        }else {
            percent = (float) 1.0;
        }
        return percent;
    }
}
